package org.balthie.demo.jdk.util.concurrent.future;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

// 简单的任务，用Future获取结果还好，但并行提交的多个异步任务，往往并不是独立的，很多时候业务逻辑处理存在串行[依赖]、并行、聚合的关系。
// CompletableFuture实现了对任务的编排能力

//描述依赖关系：
//thenApply() ：把前面异步任务的结果，交给后面的Function
//thenCompose()：用来连接两个有依赖关系的任务，结果由第二个任务返回

//描述and聚合关系：
//thenCombine：任务合并，有返回值
//thenAccepetBoth：两个任务执行完成后，将结果交给thenAccepetBoth消耗，无返回值
//runAfterBoth：两个任务都执行完成后，执行下一步操作（Runnable）

//描述or聚合关系：
//applyToEither：两个任务谁执行的快，就使用那一个结果，有返回值
//acceptEither：两个任务谁执行的快，就消耗那一个结果，无返回值
//runAfterEither：任意一个任务执行完成，进行下一步操作(Runnable)

//并行执行：
//CompletableFuture类提供了anyOf()和allOf()用于支持多个CompletableFuture并行执行

//异步操作
//public static CompletableFuture<Void> runAsync(Runnable runnable)    无返回值任务
//public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
//public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)   有返回值
//public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

//https://blog.csdn.net/tongtest/article/details/107549749

public class CompletableFutureDemo
{
    public static void main(String[] args)
    {
//        未指定线程池底层默认用了ForkJoinPool.commonPool(), 可能导致问题
//        https://blog.csdn.net/FindStar_ing/article/details/124865952
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
        
        // 任务1：洗水壶->烧开水
        CompletableFuture<Void> f1 = CompletableFuture
                .runAsync(() -> {
                    System.out.println(Thread.currentThread() + " T1:洗水壶...");
                    sleep(1, TimeUnit.SECONDS);
                    System.out.println(Thread.currentThread() + "T1:烧开水...");
                    sleep(15, TimeUnit.SECONDS);
                }, newFixedThreadPool);
        // 任务2：洗茶壶->洗茶杯->拿茶叶
        CompletableFuture<String> f2 = CompletableFuture
                .supplyAsync(() -> {
                    System.out.println(Thread.currentThread() + "T2:洗茶壶...");
                    sleep(1, TimeUnit.SECONDS);
                    
                    System.out.println(Thread.currentThread() + "T2:洗茶杯...");
                    sleep(2, TimeUnit.SECONDS);
                    
                    System.out.println(Thread.currentThread() + "T2:拿茶叶...");
                    sleep(1, TimeUnit.SECONDS);
                    return "龙井";
                });
        // 任务3：任务1和任务2完成后执行：泡茶
        CompletableFuture<String> f3 = f1.thenCombine(f2, (__, tf) -> {
            System.out.println(Thread.currentThread() + "T3:拿到茶叶:" + tf);
            System.out.println(Thread.currentThread() + "T3:泡茶...");
            return "上茶:" + tf;
        });
        // 等待任务3执行结果
        System.out.println(f3.join());
    }
    
    static void sleep(int t, TimeUnit u)
    {
        try
        {
            u.sleep(t);
        }
        catch (InterruptedException e)
        {
        }
    }
}
